import { Fragment, useState } from 'react';
import { Combobox, Transition } from '@headlessui/react';

type AutoCompleteProps<T> = {
  items: T[];
  placeholder?: string | undefined;
  toId: (item: T) => string;
  itemToString: (item: T) => string;
  onChange: (query: string) => void;
  onSelect: (item: T | undefined) => void;
  onEnter: (query: string) => void;
};

export default function AutoComplete<T>({
  items,
  placeholder,
  toId,
  itemToString,
  onChange,
  onSelect,
  onEnter,
}: AutoCompleteProps<T>) {
  const [query, setQuery] = useState('');

  const onSelectChange = (id: string) => onSelect(items.find((it) => toId(it) === id));

  return (
    <Combobox onChange={onSelectChange}>
      <div className="inline-block relative mt-1">
        <div className="relative w-full cursor-default overflow-hidden rounded-lg bg-white text-left shadow-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white/75 focus-visible:ring-offset-2 focus-visible:ring-offset-teal-300 sm:text-sm">
          <Combobox.Input
            className="w-full border-0 py-1.5 pl-3 pr-10 text-sm rounded-md shadow-sm ring-gray-300 leading-5 text-gray-900 focus:ring-0"
            displayValue={(item: T | undefined) => (!item ? '' : itemToString(item))}
            onKeyUp={(event) => {
              if (event.key === 'Enter' && items.length === 0) {
                onEnter(query);
              }
            }}
            placeholder={placeholder}
            onChange={(event): void => {
              const text = event.target.value;
              setQuery(text);
              onChange(text);
            }}
          />
          <Combobox.Button className="absolute inset-y-0 right-0 flex items-center pr-2">🔍</Combobox.Button>
        </div>
        <Transition
          as={Fragment}
          leave="transition ease-in duration-100"
          leaveFrom="opacity-100"
          leaveTo="opacity-0"
          afterLeave={() => setQuery('')}
        >
          <Combobox.Options className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm">
            {items.length === 0 && query !== '' ? (
              <div className="relative cursor-default select-none px-4 py-2 text-gray-700">
                没有此标签？按回车键创建
              </div>
            ) : (
              items.map((it) => (
                <Combobox.Option
                  key={toId(it)}
                  className={({ active }) =>
                    `relative cursor-default select-none py-1.5 px-3 ${
                      active ? 'bg-teal-600 text-white' : 'text-gray-900'
                    }`
                  }
                  value={toId(it)}
                >
                  {({ selected }) => (
                    <span className={`block truncate ${selected ? 'font-medium' : 'font-normal'}`}>
                      {itemToString(it)}
                    </span>
                  )}
                </Combobox.Option>
              ))
            )}
          </Combobox.Options>
        </Transition>
      </div>
    </Combobox>
  );
}
